#pragma once

#include <base/macro/control.h>

//      FOLDL( m, acc, a )        >>>  m( acc, a )
//      FOLDL( m, acc, a, b )     >>>  m( m( acc, a ), b )
//      FOLDL( m, acc, a, b, c )  >>>  m( m( m( acc, a ), b ), c )
//

#define FOLD_STOP			(((((((())))))))      

#define FOLDL(f, ... )			EVAL(__FOLDL0(f, __VA_ARGS__, FOLD_STOP, 0))
#define __FOLDL0( f, acc, cur, next, ... ) \
        DEFER(__MIF_ELSE(IS_PAREN(next))(SND, __FOLDL1))(f, f(acc, cur), next, __VA_ARGS__)
#define __FOLDL1( ... ) \
        DEFER(__FOLDL0)(__VA_ARGS__)

#define FOLDR(f, ... )			EVAL(__FOLDR0(f, __VA_ARGS__, FOLD_STOP, 0))
#define __FOLDR0(f, acc, cur, next, ... ) \
	f(acc, \
		DEFER(__MIF_ELSE(IS_PAREN(next))(cur __EMPTY, __FOLDR1)) \
		(f, cur, next, __VA_ARGS__))
#define __FOLDR1( ... ) \
	DEFER(__FOLDR0)(__VA_ARGS__)

